package edu.towson.cosc.cosc455.kkarolenko.markdowncompiler;

import java.util.Stack;

// Analyze a syntax tree and convert it to html
public class MSemanticAnalyzer {
	
	public Stack<Token> variable = new Stack<Token>();
	public Stack<Token> backup = new Stack<Token>();
	public String file = "";
	
	// analyze the syntax tree and convert to html
	public void travel(Node<Token> node) throws CompilerException {
		
		// if there is no node, exit
		if (node == null) {
			return;
		}
		else {
						
			// If the first child of this node is a define, push it. Its siblings need access too
			if (node.getChildren().size() > 0) {
				
				// place this node in the file
				file += node.getData().getHTML() + "\n";
				
				// push the defined variable early
				for (Node<Token> child : node.getChildren()) {
					if (child.getData().getID().equalsIgnoreCase("DEF")) {
						variable.push(child.getData());
					}
				}
			}
			else if (node.getData().getID().equalsIgnoreCase("DEF")) {
				// ignore the define nodes, we used these already
				return;
			}
			// If we need a variable to use
			else if (node.getData().getID().equalsIgnoreCase("USE")) {
				
				// If there are no variables throw an error
				if (variable.isEmpty()) {
					throw new CompilerException("No variable defined for: " + node.getData().getMD());
				}
				
				// while there are variables
				while (!variable.isEmpty()) {
					// If the top one is the variable, break and use its data
					if (variable.peek().getMD().equalsIgnoreCase(node.getData().getMD())) {
						break;
					}
					// else pop it off the top and place it in another stack for now
					backup.push(variable.pop());
				}
				
				// use the variable's data
				if (!variable.isEmpty()) {
					file += variable.peek().getHTML();
				}
				// if it is empty, throw an error
				else {
					throw new CompilerException("Semantic Error: No variable defined for: " + node.getData().getMD());
				}
				
				// while there are variables in the reserve stack, place them back on the variable stack
				while (!backup.isEmpty()) {
					variable.push(backup.pop());
				}
			}
			// Normal case, export html
			else {
				file += node.getData().getHTML() + "\n";
			}
			
			// recursively get the children
			for (Node<Token> child : node.getChildren()) {
				travel(child);
			}
			
			// if the current node is the def, pop its variable, we're done with it
			// If the first child of this node is a define, push it. Its siblings need access too
			if (node.getChildren().size() > 0) {
				
				// push the defined variable early
				for (Node<Token> child : node.getChildren()) {
					if (child.getData().getID().equalsIgnoreCase("DEF")) {
						variable.pop();
					}
				}
			}
		}
	}
	
	// return the file
	public String getFile() {
		return file;
	}
}
